package sat.component;

import java.util.LinkedList;
import java.util.List;

import org.mt4j.MTApplication;
import org.mt4j.components.TransformSpace;
import org.mt4j.components.visibleComponents.font.FontManager;
import org.mt4j.components.visibleComponents.font.IFont;
import org.mt4j.components.visibleComponents.widgets.MTTextArea;
import org.mt4j.components.visibleComponents.widgets.MTTextField;
import org.mt4j.input.inputProcessors.IGestureEventListener;
import org.mt4j.input.inputProcessors.MTGestureEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragEvent;
import org.mt4j.input.inputProcessors.componentProcessors.dragProcessor.DragProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleEvent;
import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.tapAndHoldProcessor.TapAndHoldEvent;
import org.mt4j.input.inputProcessors.componentProcessors.tapAndHoldProcessor.TapAndHoldProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapEvent;
import org.mt4j.input.inputProcessors.componentProcessors.tapProcessor.TapProcessor;
import org.mt4j.util.MTColor;
import org.mt4j.util.math.Vector3D;
import org.mt4j.util.math.Vertex;

import sat.frame.WorkPlaceScene;
import sat.model.ClassModel;

public class ClassComponent extends UMLClass{
	private static final float widthPreferred = 100;
	private static final float heightPreferred = 150;
	private static final int fontsize = 15;

	private MTTextField nameField;
	private MTTextArea attributeField;
	private MTTextArea operationField;
	private DragAndDropButton linkButton;
	private ClassComponent currentComponentHovered;
	private ClassComponent lastComponentHoverred;
	private List<Link> linkList = new LinkedList<Link>();  
	
	private double degCurrent = 0;
	private double degPrecedent = 0;

	public List<Link> getLinkList() {
		return linkList;
	}

	public void addLinkToList(Link l){
		linkList.add(l);
	}

	private float widthDynamic = widthPreferred;
	private ClassModel model;

	private ClassComponentPopUp popup;
	private ClassComponent instance;

	public enum entityType{INTERFACE,CLASS};

	private  Vector3D pos = null;

	public void showPopUp(){
		popup.setVisible(true);
		popup.setPositionRelativeToParent(new Vector3D(UMLPopUp.widthPreferred/2+widthDynamic+30,this.getHeightXY(TransformSpace.LOCAL)/2));
	}

	// refresh class view 
	public void refreshView(String name, String attributList, String operationList){
		nameField.setText(name);
		attributeField.setText(attributList);
		operationField.setText(operationList);

		String[] listAtt = attributList.split("\n");
		System.out.println("len = "+listAtt.length);
		int size = 0;
		if (name.length()>0) {
			size = name.length();	
		}
		for (int i = 0; i < listAtt.length; i++) {
			int temp = listAtt[i].length();
			if(temp >= size)
				size = temp;
		}
		String[] listOper = operationList.split("\n");
		System.out.println("len = "+listOper.length);
		for (int i = 0; i < listOper.length; i++) {
			int temp = listOper[i].length();
			if(temp >= size)
				size = temp;
		}

		float coef = 0.6f; 
		this.widthDynamic = size*fontsize*coef > ClassComponent.widthPreferred ? size*fontsize*coef : ClassComponent.widthPreferred; 
		//attributeField.getWidthXY(TransformSpace.LOCAL) > ClassComponent.widthPreferred ? attributeField.getWidthXY(TransformSpace.LOCAL) : ClassComponent.widthPreferred; 
		this.setWidthLocal(widthDynamic);
		popup.setPositionRelativeToParent(new Vector3D(UMLPopUp.widthPreferred/2+widthDynamic+30,heightPreferred/2));
		nameField.setWidthLocal(widthDynamic);

		float nameFieldHeight = (float) nameField.getHeightXY(TransformSpace.LOCAL);
		float attListHeight = (float) (listAtt.length*fontsize*1.5 > heightPreferred*2/5 ? listAtt.length*fontsize*1.5 : heightPreferred*2/5);
		float operListHeight = (float) (listOper.length*fontsize*1.5 > heightPreferred*2/5 ? listOper.length*fontsize*1.5 : heightPreferred*2/5);
		attributeField.setSizeLocal(widthDynamic, attListHeight);
		operationField.setSizeLocal(widthDynamic, operListHeight);
		this.setSizeLocal(widthDynamic, attListHeight+operListHeight+nameFieldHeight);
		operationField.setPositionRelativeToParent(new Vector3D(widthDynamic/2,attListHeight+nameFieldHeight+operListHeight/2));
	}

	public float getWidthDynamic() {
		return widthDynamic;
	}

	//refresh interface view
	public void refreshView(String name, String operationList){
		nameField.setText(name);
		operationField.setText(operationList);

		int size = 0;
		if (name.length()>0) {
			size = name.length();	
		}
		String[] listOper = operationList.split("\n");
		System.out.println("len = "+listOper.length);
		for (int i = 0; i < listOper.length; i++) {
			int temp = listOper[i].length();
			if(temp >= size)
				size = temp;
		}

		float coef = 0.6f; 
		this.widthDynamic = size*fontsize*coef > ClassComponent.widthPreferred ? size*fontsize*coef : ClassComponent.widthPreferred; 
		//attributeField.getWidthXY(TransformSpace.LOCAL) > ClassComponent.widthPreferred ? attributeField.getWidthXY(TransformSpace.LOCAL) : ClassComponent.widthPreferred; 
		this.setWidthLocal(widthDynamic);
		popup.setPositionRelativeToParent(new Vector3D(UMLPopUp.widthPreferred/2+widthDynamic+30,heightPreferred/2));

		nameField.setWidthLocal(widthDynamic );

		float nameFieldHeight = (float) nameField.getHeightXY(TransformSpace.LOCAL);
		float operListHeight = (float) (listOper.length*fontsize*1.5 > heightPreferred*2/5 ? listOper.length*fontsize*1.5 : heightPreferred*2/5);
		operationField.setSizeLocal(widthDynamic , operListHeight);
		this.setSizeLocal(widthDynamic , operListHeight+nameFieldHeight);
		operationField.setPositionRelativeToParent(new Vector3D(widthDynamic /2,nameFieldHeight+operListHeight/2));
	}

	public ClassComponent(final MTApplication mtApplication,entityType type) {
		super(mtApplication);

		instance = this;
		model = new ClassModel(this);

		IFont textFont = FontManager.getInstance().createFont(mtApplication, "Arial",//"Comic Sans MS",
				ClassComponent.fontsize, // Font size
				new MTColor(56, 62, 52, 255), // Font fill color
				true);

		nameField = new MTTextField(mtApplication, 0, 0, widthPreferred, heightPreferred/5,textFont); 

		if(type == entityType.CLASS){
			attributeField = new MTTextArea(mtApplication, 0, 0, widthPreferred, heightPreferred*2/5,textFont);
		}
		else // interface
			this.setHeightLocal(heightPreferred*3/5);

		operationField = new MTTextArea(mtApplication, 0, 0, widthPreferred, heightPreferred*2/5,textFont);


		this.setFillColor(new MTColor(215, 195, 168, 255));
		this.setStrokeColor(new MTColor(56, 62, 52, 255));
		this.setStrokeWeight(3);

		nameField.setFillColor(new MTColor(215, 195, 168, 255));
		nameField.setStrokeColor(new MTColor(56, 62, 52, 255));
		nameField.setStrokeWeight(3);

		if(type == entityType.CLASS){
			attributeField.setFillColor(new MTColor(215, 195, 168, 255));
			attributeField.setStrokeColor(new MTColor(56, 62, 52, 255));
			attributeField.setStrokeWeight(3);
		}

		operationField.setFillColor(new MTColor(215, 195, 168, 255));
		operationField.setStrokeColor(new MTColor(56, 62, 52, 255));
		operationField.setStrokeWeight(3);

		popup = new ClassComponentPopUp(mtApplication,model,type);

		this.addChild(nameField);

		//nameField.setPositionRelativeToParent(new Vector3D(width/2,height/5/2));
		linkButton = new DragAndDropButton(mtApplication,DragAndDropButton.ButtonType.LINK,"link.png");
		this.addChild(linkButton);
		linkButton.setPositionRelativeToParent(new Vector3D(-20,-20));

		//linkButton.removeAllGestureEventListeners();

		linkButton.addGestureListener(DragProcessor.class,new IGestureEventListener() {
			public boolean processGestureEvent(MTGestureEvent evt) {

				DragEvent de = (DragEvent) evt;
				switch (de.getId()) {
				case MTGestureEvent.GESTURE_STARTED:
					pos = new Vector3D(linkButton.getCenterPointRelativeToParent());
					break;
				case MTGestureEvent.GESTURE_UPDATED:
					System.out.println("updating");
					currentComponentHovered = WorkPlaceScene.getInstance().findClassComponentByPosition(linkButton.getCenterPointGlobal());
					if(currentComponentHovered != null && currentComponentHovered != instance){
						// highlight the current class hovered
						currentComponentHovered.setStrokeColor(MTColor.GREEN);
						currentComponentHovered.setNoStroke(false);
						currentComponentHovered.setStrokeWeight(10);
						lastComponentHoverred = currentComponentHovered;
					}
					else if (lastComponentHoverred != null)
						lastComponentHoverred.setNoStroke(true);
					break;
				case MTGestureEvent.GESTURE_ENDED:
					ClassComponent componentDroppedOn =  WorkPlaceScene.getInstance().findClassComponentByPosition(linkButton.getCenterPointGlobal());
					if(componentDroppedOn != null && componentDroppedOn != instance){
						Link l = new Link(mtApplication,instance,componentDroppedOn);

						instance.addLinkToList(l);
						componentDroppedOn.addLinkToList(l);
						l.getLinkLine().setDegPrec(l.getLinkLine().getCurrentDegree());
						KeyboardTextField title = l.getTitle();
						title.rotateZ(title.getCenterPointLocal(),(float)l.getLinkLine().getCurrentDegree()*180/3.1415926f, TransformSpace.LOCAL);
						WorkPlaceScene.getInstance().getCanvas().addChild(l.getLinkLine()); // add the link on the canvas
						componentDroppedOn.setNoStroke(true);
					}
					System.out.println("the component catches is = "+componentDroppedOn);
					linkButton.setPositionRelativeToParent(pos);
					break;
				default:
					break;
				}
				return false;
			}

		});

		if(type == entityType.CLASS){
			this.addChild(attributeField);
			attributeField.setPositionRelativeToParent(new Vector3D(widthPreferred/2,heightPreferred*2/5));
			this.addChild(operationField);
			operationField.setPositionRelativeToParent(new Vector3D(widthPreferred/2,heightPreferred*4/5));
		}
		else{
			this.addChild(operationField);
			operationField.setPositionRelativeToParent(new Vector3D(widthPreferred/2,heightPreferred*2/5));
		}

		this.addChild(popup);

		nameField.setPickable(false);
		if(type == entityType.CLASS)
			attributeField.setPickable(false);
		operationField.setPickable(false);

		//gesture for pop-up
		this.registerInputProcessor(new TapProcessor(mtApplication));
		this.addGestureListener(TapProcessor.class, new IGestureEventListener() {
			@Override
			public boolean processGestureEvent(MTGestureEvent ge) {
				// TODO Auto-generated method stub
				TapEvent te = (TapEvent)ge;
				if(instance.tappable){
					switch (te.getTapID()) {
					case TapEvent.TAPPED:
						System.out.println("Tapped");
						showPopUp();
						break;
					default:
						break;
					}
				}
				else
					tappable = true;
				return false;
			}
		});

		
		this.addGestureListener(DragProcessor.class, new IGestureEventListener() {
			@Override
			public boolean processGestureEvent(MTGestureEvent evt) {
				// TODO Auto-generated method stub
				DragEvent de = (DragEvent) evt;
				switch (de.getId()) {
				case MTGestureEvent.GESTURE_STARTED:
					break;
				case MTGestureEvent.GESTURE_UPDATED:
					adjustLinks();
					break;
				case MTGestureEvent.GESTURE_ENDED:
					break;
				default:
					break;
				}
				return false;
			}

		});


		this.addGestureListener(TapAndHoldProcessor.class, new IGestureEventListener() {
			@Override
			public boolean processGestureEvent(MTGestureEvent ge) {
				TapAndHoldEvent e = (TapAndHoldEvent)ge;
				if (e.getId() == TapAndHoldEvent.GESTURE_ENDED && e.isHoldComplete()){
					for (int i = 0; i < linkList.size(); i++) {
						linkList.get(i).getLinkLine().destroy();
					}
					instance.destroy();
				}
				return false;
			}
		});

		this.addGestureListener(ScaleProcessor.class, new IGestureEventListener() {
			@Override
			public boolean processGestureEvent(MTGestureEvent evt) {
				ScaleEvent e = (ScaleEvent) evt;
				switch (e.getId()) {
				case MTGestureEvent.GESTURE_STARTED:
					break;
				case MTGestureEvent.GESTURE_UPDATED:

					System.out.println("scaling...");
					System.out.println("instance.getHeightXY(TransformSpace.LOCAL) --- "+instance.getHeightXY(TransformSpace.GLOBAL)+" --- "+heightPreferred);
					System.out.println("instance.getWidthXY(TransformSpace.LOCAL) --- "+instance.getWidthXY(TransformSpace.GLOBAL)+" --- "+widthPreferred);

					if(instance.getHeightXY(TransformSpace.GLOBAL) < heightPreferred
							&& instance.getWidthXY(TransformSpace.GLOBAL) < widthPreferred){
						instance.setSizeXYGlobal(widthPreferred, heightPreferred);
					}

					adjustLinks();
					break;
				case MTGestureEvent.GESTURE_ENDED:
					break;
				}
				return false;
			}
		});
		this.removeAllGestureEventListeners(RotateProcessor.class);

	}
	public void adjustLinks(){
		for (int i = 0; i < linkList.size(); i++) {
			degCurrent = linkList.get(i).getLinkLine().getCurrentDegree();
			Vertex[] v = new Vertex[]{
					new Vertex(instance.getPosition(TransformSpace.GLOBAL).x,instance.getPosition(TransformSpace.GLOBAL).y),
					new Vertex(linkList.get(i).getLinkLine().getEntity2() == instance ? linkList.get(i).getLinkLine().getEntity1Centre() : 
						linkList.get(i).getLinkLine().getEntity2Centre())
			};
			linkList.get(i).getLinkLine().setVertices(v);
			Vector3D linkTitlePos = new Vector3D(
					linkList.get(i).getLinkLine().getCenterPointGlobal().x+20,
					linkList.get(i).getLinkLine().getCenterPointGlobal().y-20
					) ;
			//			linkList.get(i).getLinkLine().
			KeyboardTextField title = linkList.get(i).getTitle();
			System.out.println("DEGREE = "+(degCurrent)*180/3.1415926f);
			title.rotateZ(title.getCenterPointLocal(),(float)((degCurrent - linkList.get(i).getLinkLine().getDegPrec())*180/3.1415926f) , TransformSpace.LOCAL);
			linkList.get(i).getLinkLine().setDegPrec(degCurrent);
			linkList.get(i).getTitle().setPositionGlobal(linkTitlePos);
		}
	}
}
